/*
 * UDPThread.cpp
 *
 *  Created on: 18.03.2011
 *      Author: niea
 */

#include "UDPThread.hpp"


using namespace efs;

UDPThread::UDPThread(Settings const& settings)
	: m_settings(settings)
	, m_stop_req(false)
{
}

UDPThread::~UDPThread()
{
}

void UDPThread::printError(std::string func_name) const
{
	std::string msg = strerror(errno);
	pantheios::log_ERROR("UDP pinger socket error - " + func_name + ": " + msg);
}

// this function starts main thread function "ping()"
void * UDPThread::threadProcStarter(void *base_class_pointer)
{
	static_cast<UDPThread*> (base_class_pointer)->threadProc();
	return 0;
}

bool UDPThread::prepareSocket()
{
	// new socket for request receive
	//m_socket = socket (AF_INET, SOCK_STREAM, IPPROTO_UDP);
	m_socket = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP);

	if (m_socket < 0)
	{
		printError("socket");
		return false;
	}

	// non-blocking mode
	fcntl(m_socket, F_SETFL, O_NONBLOCK);

	// setting address and m_port
	memset(&m_sockaddr, 0, sizeof(m_sockaddr));
	m_sockaddr.sin_family = AF_INET;
	m_sockaddr.sin_port = htons (m_settings.udp_port);
	m_sockaddr.sin_addr.s_addr = INADDR_ANY;

	// this operation prevents "Address already in use" error
	int tr = 1;
	if (setsockopt(m_socket, SOL_SOCKET, SO_REUSEADDR, &tr, sizeof(int)) == -1)
	{
		printError("setsockopt");
		return false;
	}

	if (bind(m_socket, (struct sockaddr *)&m_sockaddr, sizeof(m_sockaddr)) < 0)
	{
		printError("bind");
		return false;
	}
	return true;
}

void UDPThread::closeAll()
{
	if (m_socket)
	{
		close(m_socket);
		m_socket = 0;
	}
	pantheios::log_INFORMATIONAL("UDP thread stop");
}

bool UDPThread::start()
{
	if (!prepareSocket())
	{
		closeAll();
		pantheios::log_ERROR("UDP thread starting - error preparing socket");
		return false;
	}
	if (pthread_create (&m_thread, NULL, UDPThread::threadProcStarter, (void*)this))
	{
		closeAll();
		pantheios::log_ERROR("UDP thread starting - error creating thread");
		return false;
	}
	pantheios::log_INFORMATIONAL("UDP thread start");
	return true;
}

void UDPThread::stop()
{
	pantheios::log_INFORMATIONAL("UDP thread stop request");
	m_stop_req = true;
	pthread_join(m_thread, NULL);
}
